package com.abc.tacos.controller;

import com.abc.tacos.bean.Ingredient;
import com.abc.tacos.bean.Ingredient.Type;
import com.abc.tacos.bean.Order;
import com.abc.tacos.bean.Taco;
import com.abc.tacos.dao.IngredientRepository;
import com.abc.tacos.dao.TacoRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Kar
 * @create 2022-04-13 下午4:38
 */
@Slf4j
@Controller
@SessionAttributes("order")
@RequestMapping("/design")
public class DesignTacoController {

    /**
     * 对于必需的依赖，建议使用基于构造函数的注入，设置它们为不可变的，并防止它们为null。对于可选的依赖项，建议使用基于sett的注入。
     */
    private final IngredientRepository ingredientRepository;

    private final TacoRepository designRepository;

    /**
     * 基于构造函数的依赖注入:
     * 1. @Autowired注解也是可以省去的。
     * 2. 基于构造函数注入的主要优点是可以将需要注入的字段声明为final， 使得它们会在类实例化期间被初始化，这对于所需的依赖项很方便。
     *
     * @param ingredientRepository
     * @param designRepository
     */
    public DesignTacoController(IngredientRepository ingredientRepository, TacoRepository designRepository) {
        this.ingredientRepository = ingredientRepository;
        this.designRepository = designRepository;
    }

    @ModelAttribute(name = "order")
    public Order order() {
        return new Order();
    }

    @ModelAttribute(name = "taco")
    public Taco taco() {
        return new Taco();
    }

    @ModelAttribute
    public void groupIngredients(Model model) {
        // 从数据库中获取Ingredient信息
        ArrayList<Ingredient> ingredients = new ArrayList<>();
        ingredientRepository.findAll().forEach(ingredients::add);

        Type[] types = Type.values();
        for (Type type : types) {
            // 对Ingredients分组
            model.addAttribute(
                    type.toString().toLowerCase(),
                    filterByType(ingredients, type));
        }
    }

    @GetMapping
    public String showDesignForm() {
        // model.addAttribute("design", new Taco());
        return "design";
    }

    /**
     * @param design 订单数据，spring默认为其绑定请求中的数据
     * @param errors 绑定过程中出现的格式匹配异常
     * @param order  使用SessionAttribute防止spring绑定请求参数
     * @return 重定向至订单页面
     */
    @PostMapping
    public String processDesign(
            @Valid Taco design,
            Errors errors,
            @SessionAttribute Order order) {

        if (errors.hasErrors()) {
            return "design";
        }
        Taco saved = designRepository.save(design);
        // 保存到session域中
        order.addDesign(saved);
        return "redirect:/orders/current";
    }

    /**
     * 根据Type筛选出对应的Ingredient列表
     *
     * @param ingredients
     * @param type
     * @return
     */
    private List<Ingredient> filterByType(List<Ingredient> ingredients, Type type) {
        return ingredients
                .stream()
                .filter(x -> x.getType().equals(type))
                .collect(Collectors.toList());
    }
}
